package predicate;

import function.unary.UnaryFunction;
import function.unary.UnaryPredicate;

/**
 *
 * @author Shimu
 * @date 29-Oct-2012
 */
public class PredicateFunctions {

    /**
     * PredicateFunctions class has no instance methods. Only public static
     * methods. Private constructor to prevent creating PredicateFunctions
     * instances.
     */
    private PredicateFunctions() {
    }
    
    /**
     * Given an arbitrary element of type T, returns an UnaryPredicate that
     * takes an element of type T as argument and always returns true.
     * 
     * @param <T> an arbitrary element of type T (an arbitrary element is needed
     * so Java can enforce typing at compile time)
     */
    public static <T> UnaryPredicate<T> alwaysTrue(T element) {
        return new UnaryPredicate<T>() {

            public Boolean evaluate(T arg) {
                return true;
            }            
        };
    } 
    
    /**
     * Given an arbitrary element of type T, returns an UnaryPredicate that
     * takes an element of type T as argument and always returns false.
     * 
     * @param <T> an arbitrary element of type T (an arbitrary element is needed
     * so Java can enforce typing at compile time)
     */
    public static <T> UnaryPredicate<T> alwaysFalse(T element) {
        return new UnaryPredicate<T>() {

            public Boolean evaluate(T arg) {
                return false;
            }            
        };
    }
    
    /**
     * Returns a UnaryPredicate that wraps around the given fcn.
     * The returned UnaryPredicate returns true if and only if the given
     * fcn returns true. 
     * @param <T>
     * @param fcn
     * @return 
     */
    public static <T> UnaryPredicate<T> toPredicate(
            final UnaryFunction<T, Boolean> fcn) {
        return new UnaryPredicate<T>() {
            public Boolean evaluate(T arg) {
                return fcn.evaluate(arg);
            }
            
        };
    }
    
    /**
     * Returns a UnaryPredicate that returns true if and only if a given
     * Object equals obj.
     * 
     * @param <T>
     * @param obj
     * @return 
     */
    public static <T> UnaryPredicate<T> equal(final T obj) {
        return new UnaryPredicate<T>() {
            public Boolean evaluate(T arg) {
                return obj.equals(arg);
            }
        };
    }
    
    /**
     * Returns the complement of the given UnaryFunction (i.e. the returned
     * function returns true if and only if the given function returns false).
     * 
     * @param <T>
     * @param predicate
     * @return 
     */
    public static <T> UnaryPredicate<T> complement(
            final UnaryPredicate<T> predicate) {
        return new UnaryPredicate<T>() {

            public Boolean evaluate(T arg) {
                return !predicate.evaluate(arg);
            }
        };
    }
    
    /**
     * Returns a UnaryPredicate that returns true if and only if all of the
     * given predicates return true. Exhibits short circuiting behavior (i.e.
     * the returned predicate returns false as soon as one of the predicate
     * given returns false, without checking the rest). Checks the given 
     * predicates in the order they are passed as arguments. 
     * 
     * @param <T>
     * @param predicates
     * @return 
     */
    public static <T> UnaryPredicate<T> and(final UnaryPredicate<T>... predicates) {
        return new UnaryPredicate<T>() {

            public Boolean evaluate(T arg) {
                for (UnaryPredicate<T> predicate: predicates) {
                    if (!predicate.evaluate(arg)) {
                        return false;
                    }
                }
                return true;
            }            
        };
    }
    
    /**
     * Returns a UnaryPredicate that returns true if and only if one of the
     * given predicates return true. Exhibits short circuiting behavior (i.e.
     * the returned predicate returns true as soon as one of the predicate
     * given returns true, without checking the rest). Checks the given 
     * predicates in the order they are passed as arguments. 
     * 
     * @param <T>
     * @param predicates
     * @return 
     */
    public static <T> UnaryPredicate<T> or(final UnaryPredicate<T>... predicates) {
        return new UnaryPredicate<T>() {

            public Boolean evaluate(T arg) {
                for (UnaryPredicate<T> predicate: predicates) {
                    if (predicate.evaluate(arg)) {
                        return true;
                    }
                }
                return false;
            }            
        };
    }
}
